package com.yy.train.ticket.train.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yy.train.ticket.goout.LineLinkSection;
import com.yy.train.ticket.goout.LineSection;
import com.yy.train.ticket.goout.TicketTable;
import com.yy.train.ticket.goout.TrainSeat;
import com.yy.train.ticket.into.*;
import com.yy.train.ticket.into.page.LineSectionPage;
import com.yy.train.ticket.into.page.TicketPage;
import com.yy.train.ticket.train.dao.*;
import com.yy.train.ticket.train.entity.*;
import com.yy.train.ticket.train.service.TtTicketService;
import com.yy.train.ticket.utils.ArithmeticUtils;
import com.yy.train.ticket.utils.R;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.stream.Collectors;


@Service("ttTicketService")
public class TtTicketServiceImpl extends ServiceImpl<TtTicketDao, TtTicketEntity> implements TtTicketService {

    @Resource
    TtTicketDao ttTicketDao;
    @Resource
    TtLineDao ttLineDao;
    @Resource
    TtLineSectionDao ttLineSectionDao;
    @Resource
    TtTrainSeatDao ttTrainSeatDao;
    @Resource
    TtLineStationDao ttLineStationDao;
    @Resource
    TtTrainRunSeatDao ttTrainRunSeatDao;
    @Resource
    TtTrainRunDateDao ttTrainRunDateDao;
    @Resource
    TtLineLinkSectionDao  TtLineLinkSectionDao;
    @Resource
    TtLineLinkDao ttLineLinkDao ;
    /**
     *  这是自动生成车票会出现的车票组成方式
     [1,2,3,4,5,6]

     [12,3,4,5,6]

     [123,4,5,6]
     [1234,5,6]
     [12345,6]
     [123456]
     [12,34,5,6]
     [12,345,6]
     [12,3456]

     [12,34,56]

            [12,3,45,6]	 [12,3,456]
            [12,3,4,56]
     [1,23,4,5,6]       	[1,23,45,6] 	[1,23,456]
     [1,23,4,56]
     [1,2,34,5,6]
     [1,2,3,45,6]
     [1,2,3,4,56]


     [1,234,5,6]
     [1,2,345,6]
     [1,2,3,456]

     [1234,56]
     [1,2345,6]
     [1,2,3456]

     [1,23456]

     */
/*    @Override
    public R automaticSaveTicke(Long lineId) {
        List<TtLineStationEntity> li1 = ttLineStationDao.selectList(Wrappers.<TtLineStationEntity>lambdaQuery()
                .eq(TtLineStationEntity::getLineId,lineId));
        List<TtLineSectionEntity> li = ttLineSectionDao.selectList(Wrappers.<TtLineSectionEntity>lambdaQuery()
                .eq(TtLineSectionEntity::getLineId,lineId));

        List<TtLineSectionEntity> lslist = new ArrayList<>();
        for (TtLineStationEntity ttLineStationEntity : li1) {
            Long stationId = ttLineStationEntity.getStationId();
            for (TtLineSectionEntity ttLineSectionEntity : li) {
                Long startStationId = ttLineSectionEntity.getStartStationId();
                if (Objects.equals(stationId, startStationId)) {
                    lslist.add(ttLineSectionEntity);
                }
            }
        }
        Map<Long, List<TtLineSectionEntity>> map = lslist.stream().collect(Collectors.groupingBy(TtLineSectionEntity::getStartStationId));

        Long startStationId = li1.get(0).getStationId();
        Long endStationId = li1.get(li1.size() - 1).getStationId();

        TtLineSectionEntity [] lineSectionlist =new TtLineSectionEntity[li1.size()];

        List<TtLineSectionEntity []> list=new ArrayList<>();
        extracted(startStationId,endStationId, map, lineSectionlist,list,0);

return R.ok(list);

    }*/

   /* private static void extracted(Long staId,Long endStaId, Map<Long, List<TtLineSectionEntity>> map,  TtLineSectionEntity [] lineSectionlist,  List<TtLineSectionEntity []> list,int n) {
        for (Map.Entry<Long, List<TtLineSectionEntity>> entry : map.entrySet()) {
            Long stationId = entry.getKey();
            if (Objects.equals(staId, stationId)) {
                for (int i = 0; i <entry.getValue().size() ; i++) {
                    TtLineSectionEntity ttLineSectionEntity = entry.getValue().get(i);
                    Long endStationId = ttLineSectionEntity.getEndStationId();
                    System.out.print(ttLineSectionEntity.getLineSectionName()+" -->  ");
                    lineSectionlist[n]=ttLineSectionEntity;
                    if (Objects.equals(endStaId, endStationId)) {
                        System.out.println("-----"+n);
                        TtLineSectionEntity [] string=new TtLineSectionEntity[n+1];
                        for (int j = 0; j <= n; j++) {
                            string[j]= lineSectionlist[j];

                        }
                        list.add(string);
                    }else {
                        extracted(endStationId,endStaId, map, lineSectionlist,list,n+1);
                    }
                }
            }
        }
    }*/




    @Override
    public R saveTicke(SeatTicket seatTicket) {
        List<Long> runSeatIds = seatTicket.getRunSeatIds();
        Long runDateId = seatTicket.getRunDateId();
        Long numberId = seatTicket.getNumberId();
        List<TtLineStationEntity> li1 = ttLineStationDao.numberLineStation(numberId);
        TtTrainRunDateEntity ttTrainRunDateEntity = this.ttTrainRunDateDao.selectById(runDateId);
        List<TtTicketEntity> list = new ArrayList<>();
        for (Long runSeatId : runSeatIds) {
            TtTrainRunSeatEntity ttTrainRunSeatEntity = this.ttTrainRunSeatDao.selectById(runSeatId);

            List<TtLineSectionEntity> li = ttLineSectionDao.selectBatchIds(seatTicket.getSectionIds());
            List<Long> stationIds = li1.stream().map(TtLineStationEntity::getStationId).collect(Collectors.toList());
            List<Long> startStationIds = li.stream().map(TtLineSectionEntity::getStartStationId).collect(Collectors.toList());
            List<Long> endStationIds = li.stream().map(TtLineSectionEntity::getEndStationId).collect(Collectors.toList());
            boolean b1 = startStationIds.stream()
                    .allMatch(add -> stationIds.stream()
                            .anyMatch(all -> Objects.equals(add, all)
                            ));
            boolean b2 = endStationIds.stream()
                    .allMatch(add -> stationIds.stream()
                            .anyMatch(all -> Objects.equals(add, all)
                            ));
            if (b1 && b2) {
                List<TtLineSectionEntity> list2 = lineSectionLinked(li1, li);
                TtTicketEntity ttTicketEntity;
                for (TtLineSectionEntity ls : list2) {
                    Long sectionId = ls.getSectionId();
                    ttTicketEntity = new TtTicketEntity();
                    ttTicketEntity.setRunSeatId(runSeatId);
                    ttTicketEntity.setSectionId(sectionId);
                    ttTicketEntity.setStartStationId(ls.getStartStationId());
                    ttTicketEntity.setEndStationId(ls.getEndStationId());
                    ttTicketEntity.setPrice(ls.getPrice());
                    ttTicketEntity.setRunDateId(ttTrainRunSeatEntity.getRunDateId());
                    ttTicketEntity.setNumberId(ttTrainRunSeatEntity.getNumberId());
                    ttTicketEntity.setSeatId(ttTrainRunSeatEntity.getSeatId());
                    ttTicketEntity.setRunDate(ttTrainRunDateEntity.getRunDate());
                    ttTicketEntity.setRunTime(ttTrainRunDateEntity.getRunTime());
                    ttTicketEntity.setSell(0);
                    list.add(ttTicketEntity);
                }
            } else {
                return R.error("存在非线路的站点");
            }
        }
        try {
            Long l1=System.currentTimeMillis();

            insertTicketEntity(list);

            Long l2=System.currentTimeMillis();
            System.out.println("耗时："+(l2-l1));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return R.ok();
    }
    public void insertTicketEntity(List<TtTicketEntity> list) throws InterruptedException {
        // 请求总数
        int clientTotal = list.size();
        // 同时并发执行的线程数
        int threadTotal = 200;
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            TtTicketEntity ttTicketEntity=list.get(i);
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    this.ttTicketDao.insert(ttTicketEntity);
                    semaphore.release();
                } catch (Exception e) {
                    System.out.println( e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();

    }

    @Override
    public R ticketSectionSeat(Long runDateId) {
        return R.ok(ttTicketDao.ticketSectionSeat(runDateId));
    }

    @Override
    public R ticketPage(TicketPage ticketPage) {
        //return R.ok(this.ttTicketDao.ticketPage(ticketPage));
        Page<TicketPage> page = new Page<>(ticketPage.getPageNum(), ticketPage.getPageSize());
        Integer type = ticketPage.getType();
        IPage<TicketTable> list;
        if (Objects.equals(type,1)){
            list = ttTicketDao.ticketPage(page, ticketPage);
        }else {
            list = ttTicketDao.ticketTrainPage(page, ticketPage);
        }
        return R.ok(list);

    }



    @Override
    public R automatic(LineLinkRadio lineLinkRadio) {
        List<LinkRadio> linkRadios = lineLinkRadio.getLinkRadios();
        Long runDateId = lineLinkRadio.getRunDateId();
        Long lineId = lineLinkRadio.getLineId();
        List<TtTrainRunSeatEntity> list3 = this.ttTrainRunSeatDao.selectList(Wrappers.<TtTrainRunSeatEntity>lambdaQuery().eq(TtTrainRunSeatEntity::getRunDateId, runDateId).orderByAsc(TtTrainRunSeatEntity::getBoxId).orderByAsc(TtTrainRunSeatEntity::getSeatId));
        if (list3.isEmpty()) {
            throw new RuntimeException("请先生成座位");
        }
        TtTrainRunDateEntity ttTrainRunDateEntity = this.ttTrainRunDateDao.selectById(runDateId);

        List<LineLink> list=   ttLineLinkDao.linelinklist(lineId);
        List<TtTicketEntity> list4=new ArrayList<>();
int seatNo =0;
        for (LinkRadio lr:linkRadios) {
            BigDecimal radio = lr.getRadio();
            BigDecimal size =  new   BigDecimal(list3.size());
            Long linkId = lr.getLinkId();
            BigDecimal radio1 = ArithmeticUtils.div(radio,    new   BigDecimal(100));
            int div = ArithmeticUtils.mul(size,    radio1,2).intValue();

            for (int i = seatNo; i <seatNo+div ; i++) {
                TtTrainRunSeatEntity ttTrainRunSeatEntity = list3.get(i);
                Long runSeatId = ttTrainRunSeatEntity.getRunSeatId();
                for (LineLink lineLink:list) {
                    Long linkId2 = lineLink.getLinkId();
                    if (Objects.equals(linkId2 , linkId)) {
                        TtTicketEntity ttTicketEntity;
                    for (LineLinkSection lineLinkSection : lineLink.getLineLinkSections()) {
                        ttTicketEntity = new TtTicketEntity();
                        ttTicketEntity.setRunSeatId(runSeatId);
                        ttTicketEntity.setSectionId(lineLinkSection.getSectionId());
                        ttTicketEntity.setStartStationId(lineLinkSection.getStartStationId());
                        ttTicketEntity.setEndStationId(lineLinkSection.getEndStationId());
                        ttTicketEntity.setPrice(lineLinkSection.getPrice());
                        ttTicketEntity.setRunDateId(ttTrainRunSeatEntity.getRunDateId());
                        ttTicketEntity.setNumberId(ttTrainRunSeatEntity.getNumberId());
                        ttTicketEntity.setSeatId(ttTrainRunSeatEntity.getSeatId());
                        ttTicketEntity.setRunDate(ttTrainRunDateEntity.getRunDate());
                        ttTicketEntity.setRunTime(ttTrainRunDateEntity.getRunTime());
                        ttTicketEntity.setSell(0);
                        list4.add(ttTicketEntity);
                    }
                    }
                }
            }
            seatNo=seatNo+div;

        }
       /* for (TtTicketEntity ttTicketEntity: list4) {
            this.ttTicketDao.insert(ttTicketEntity);
        }*/
        try {
            insertTicketEntity(list4);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return R.ok();
    }


    public List<TtLineSectionEntity> lineSectionLinked(List<TtLineStationEntity> stationlist, List<TtLineSectionEntity> lineSectionEntitylist) {
        List<TtLineSectionEntity> lslist = new ArrayList<>();
        for (TtLineStationEntity ttLineStationEntity : stationlist) {
            Long stationId = ttLineStationEntity.getStationId();
            for (TtLineSectionEntity ttLineSectionEntity : lineSectionEntitylist) {
                Long startStationId = ttLineSectionEntity.getStartStationId();
                if (Objects.equals(stationId, startStationId)) {
                    lslist.add(ttLineSectionEntity);
                }
            }
        }
        List<TtLineSectionEntity> lineSectionlist = new ArrayList<>();
        Long edId;
        for (int i = 0; i < stationlist.size(); i++) {
            TtLineStationEntity ttLineStationEntity=stationlist.get(i);
            TtLineSectionEntity lineSectionEntity = endStationId(lslist,ttLineStationEntity);
            if (lineSectionEntity != null) {
                edId = lineSectionEntity.getEndStationId();
                lineSectionlist.add(lineSectionEntity);
                TtLineStationEntity lineStationEntity=  endStationId3(stationlist,edId);
                i=lineStationEntity.getSeq()-1;
            }
        }

        return lineSectionlist;

    }
    public TtLineSectionEntity endStationId(List<TtLineSectionEntity> lineSectionlist,TtLineStationEntity ttLineStationEntity) {
        Long stationId = ttLineStationEntity.getStationId();
        for (TtLineSectionEntity lineSection : lineSectionlist) {
            Long  startStationId = lineSection.getStartStationId();
            if (Objects.equals(startStationId, stationId)) {
                return lineSection;
            }
        }
        return null;
    }
    public TtLineStationEntity endStationId3(List<TtLineStationEntity> stationlist,Long endId) {

        for (TtLineStationEntity station : stationlist) {
            Long stationId = station.getStationId();
            if (Objects.equals(endId, stationId)) {
                return station;
            }
        }
        return null;
    }
}